﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using System.Windows.Forms;

namespace Client
{
    /// <summary>
    /// This class provides basic client side read/write services
    /// </summary>
    public class NetworkServices
    {
        /// <summary>
        /// The client socket
        /// </summary>
        private TcpClient client;

        /// <summary>
        /// The input (read) stream on the socket
        /// </summary>
        private StreamReader input;

        /// <summary>
        /// The output (write) stream on the socket
        /// </summary>
        private StreamWriter output;

        /// <summary>
        /// Event delegate for notifying anyone who cares about a message being received on the socket
        /// </summary>
        /// <param name="sender">The class sending the event</param>
        /// <param name="args">The arguments to pass</param>
        public delegate void ServerMessageReceived(object sender, ServerEventArgs args);
        public event ServerMessageReceived OnMessageReceived;

        /// <summary>
        /// Event delegate for notifying anyone who cares about the server being disconnected
        /// </summary>
        /// <param name="sender"></param>
        public delegate void ServerDisconnected(object sender);
        public event ServerDisconnected OnDisconnected;

        /// <summary>
        /// The thread running to get input from the server.  We need this because readLine blocks
        /// </summary>
        Thread listeningThread;

        /// <summary>
        /// Creates a new instance of NetworkServices, create the new socket, open the streams and start the
        /// thread that listens for servers messages
        /// </summary>
        /// <param name="host"></param>
        /// <param name="port"></param>
        public NetworkServices(string host, int port)
        {
            // DONE: Put code here to initialize the client socket and create the input and output streams
            client = new TcpClient(host, port);
            NetworkStream nstream = client.GetStream();
            input = new StreamReader(nstream);
            output = new StreamWriter(nstream);

            // Start up our listening thread
            listeningThread = new Thread(new ThreadStart(Read));
            listeningThread.Start();
        }

        /// <summary>
        /// The method that waits for server messages.  We basically loop forever waiting for a 
        /// message from the server.  When we get it, we notify everyone who is registered to 
        /// get that message.
        /// </summary>
        public void Read()
        {
            while (true)
            {
                try
                {
                    ServerEventArgs args = new ServerEventArgs(input.ReadLine());
                    if (OnMessageReceived != null)
                    {
                        OnMessageReceived(this, args);
                    }
                }
                catch (IOException ex)
                {
                    MessageBox.Show("Socket read error, probably unexpected server shutdown\n\n" + ex.Message, 
                        "Connection error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);

                    if (OnDisconnected != null)
                    {
                        OnDisconnected(this);
                    }

                    // escape the loop, we're done here
                    break;
                }
            }
        }

        /// <summary>
        /// Write a message out on the stream, this is what you call to send something to the server
        /// </summary>
        /// <param name="message">the message to write</param>
        public void Write(string message)
        {
            // DONE: Put code here to write to the output stream
            output.WriteLine(message);
            output.Flush();
        }

        /// <summary>
        /// Shutdown threads and sockets
        /// </summary>
        public void Shutdown()
        {
            listeningThread.Abort();
            input.Close();
            output.Close();
            client.Close();
        }
    }
}
